using System.Diagnostics;
using rsync;

namespace rsync
{
    /// <summary>
    /// SessionAction是一个必须完成的动作，它给Session一个机会与其他会话同步。
    /// </summary>
    public abstract class SessionAction
    {
        /// <summary>
        /// Frame this action refers to.
        /// </summary>
        public int Frame;
    }

    /// <summary>
    /// SessionLoadGameAction是当Session需要你的游戏回滚到前一帧时你必须完成的动作。
    /// </summary>
    public class SessionLoadGameAction : SessionAction
    {
        private readonly StateStorage _storage;

        internal SessionLoadGameAction(int frame, StateStorage storage)
        {
            Debug.Assert(frame >= 0);

            Frame = frame;
            _storage = storage;
        }

        public byte[] Load()
        {
            return _storage.LoadFrame(Frame).Buffer;
        }

        public override string ToString() { return $"{typeof(SessionLoadGameAction)}: {new { Frame, _storage }}"; }
    }

    /// <summary>
    /// SessionSaveGameAction是一个你必须完成的动作，当Session需要保存你的游戏状态时，如果它以后需要回滚到那个帧。
    /// </summary>
    public class SessionSaveGameAction : SessionAction
    {
        private readonly StateStorage _storage;

        internal SessionSaveGameAction(int frame, StateStorage storage)
        {
            Debug.Assert(frame >= 0);

            Frame = frame;
            _storage = storage;
        }

        public void Save(byte[] stateBuffer)
        {
            _storage.SaveFrame(Frame, stateBuffer);
        }

        public override string ToString() { return $"{typeof(SessionSaveGameAction)}: {new { Frame, _storage }}"; }
    }

    /// <summary>
    /// SessionAdvanceFrameAction是当会话需要游戏向前推进时必须完成的动作:执行正常更新或重新模拟旧帧。
    /// </summary>
    public class SessionAdvanceFrameAction : SessionAction
    {
        public byte[] Inputs;

        internal SessionAdvanceFrameAction(int frame, byte[] inputs)
        {
            Debug.Assert(inputs != null);

            Frame = frame;
            Inputs = inputs;
        }

        public override string ToString() { return $"{typeof(SessionAdvanceFrameAction)}: {new { Frame, Inputs }}"; }
    }
}
